/**
 * Created by wzl on 2017/4/16.
 */
import React, {Component} from 'react';
import * as THREE from 'three';
import {project,degree2radian,frustumIntersectTiles} from './util/util'
import TileManager from './managers/TileManager'


class MapboxThree extends Component {
    constructor(){
        super();
        this.state={
            cameraPositionInDegrees:{lon:-74.014892578125,lat:40.701463603604594,height:1000},
            tiles:null,
            scene:null,
            camera:null,
            renderer:null,
            paning:false,
            mouseStart:null,
            mouseEnd:null,
            rotation:false,
        }
    }
    renderer=null;
    camera=null;
    scene=null;
    frustum=new THREE.Frustum();
    componentWillMount() {
        console.log('componentWillMount');
        let scene = new THREE.Scene();
        let camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 2000 );

        const cameraPositionInDegrees=this.state.cameraPositionInDegrees;
        const camerapositionInMeters = project(degree2radian(cameraPositionInDegrees.lon),degree2radian(cameraPositionInDegrees.lat),cameraPositionInDegrees.height);
        // console.log(camerapositionInMeters);
        camera.position.set(camerapositionInMeters.x,camerapositionInMeters.y,camerapositionInMeters.z);
        camera.lookAt(new THREE.Vector3(camerapositionInMeters.x,camerapositionInMeters.y,0));

        // let renderer = new THREE.WebGLRenderer({canvas:this.webglCanvas});
        // renderer.setSize( window.innerWidth, window.innerHeight );
        // renderer.setClearColor( new THREE.Color('rgb(230, 228, 224)'), 1 );

        camera.updateMatrix(); // make sure camera's local matrix is updated
        camera.updateMatrixWorld(); // make sure camera's world matrix is updated
        camera.matrixWorldInverse.getInverse( camera.matrixWorld );
        this.frustum.setFromMatrix( new THREE.Matrix4().multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ) );
        // console.log(frustum);
        let tiles = frustumIntersectTiles(this.frustum);

        // this.setState({camera:camera,scene:scene,tiles:tiles});
        this.setState({tiles:tiles});
        this.camera=camera;
        this.scene=scene;
    }
    componentDidMount() {
        console.log('componentDidMount');
        let renderer = new THREE.WebGLRenderer({canvas:this.webglCanvas});
        renderer.setSize( window.innerWidth, window.innerHeight );
        renderer.setClearColor( new THREE.Color('rgb(230, 228, 224)'), 1 );

        // this.setState({renderer:renderer});
        this.renderer=renderer;
    }
    componentWillReceiveProps(props){
        console.log('componentWillReceiveProps');
    }
    componentDidUpdate(){
        console.log('componentDidUpdate');
        let scene=this.scene;
        let camera = this.camera;
        let renderer = this.renderer;
        if (scene && renderer && camera){
            renderer.render(scene,camera);
        }
    }

    handleViewChange=()=>{
        let camera = this.camera;

        camera.updateMatrix(); // make sure camera's local matrix is updated
        camera.updateMatrixWorld(); // make sure camera's world matrix is updated
        camera.matrixWorldInverse.getInverse( camera.matrixWorld );

        this.frustum.setFromMatrix( new THREE.Matrix4().multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ) );
        // console.log(frustum);
        let tiles = frustumIntersectTiles(this.frustum);
        this.setState({tiles:tiles});
    }
    handleMouseDown=(e)=>{
        if(e.nativeEvent.which===1){
            this.setState({mouseStart:[e.clientX,e.clientY],paning:true});
        }
        else if(e.nativeEvent.which===3){
            this.setState({mouseStart:[e.clientX,e.clientY],rotation:true});
        }
    }
    handleMouseUp=(e)=>{
        this.setState({mouseEnd:[e.clientX,e.clientY],paning:false,rotation:false});
        this.handleViewChange();
    }
    handleMouseMove=(e)=>{
        if(this.state.paning){
            let start = this.state.mouseStart;
            let end = [e.clientX,e.clientY];
            let dx = end[0]-start[0];
            let dy = end[1]-start[1];

            let camera = this.camera;
            // let renderer = this.state.renderer;
            camera.position.x-=dx/this.webglCanvas.width*1000;
            camera.position.y+=dy/this.webglCanvas.height*1000;

            this.setState({
                mouseStart:end,
                // camera:camera
            });
            // this.handleViewChange();
        }
        else if(this.state.rotation){
            let start = this.state.mouseStart;
            let end = [e.clientX,e.clientY];
            let dx = end[0]-start[0];
            let dy = end[1]-start[1];

            let camera = this.camera;
            // let renderer = this.state.renderer;
            camera.rotation.y+=dx/this.webglCanvas.width * Math.PI;
            camera.rotation.x-=dy/this.webglCanvas.height* Math.PI;

            this.setState({
                mouseStart:end,
                // camera:camera
            });
            // this.handleViewChange();
        }
    }
    handleWheel=(e)=>{
        let startPos = this.camera.position;
        let direction = this.camera.getWorldDirection();
        let distance = -e.deltaY;

        let newPos = new THREE.Vector3();
        newPos.addVectors ( startPos, direction.multiplyScalar( distance ) );
        let camera = this.camera;
        // let renderer = this.state.renderer;
        camera.position.set(newPos.x,newPos.y,newPos.z);
        // this.setState({
        //     camera:camera
        // });
        this.handleViewChange();
    }

    tileShouldUpdate=()=>{
        console.log('tileShouldUpdate');
        let renderer = this.renderer;
        renderer.render(this.scene,this.camera);
    }
    render() {
        console.log('render');
        return (
            <div>
                <canvas
                    // style={{width:'300px',height:'300px'}}
                    ref={element=>this.webglCanvas=element}
                    onMouseDown={this.handleMouseDown}
                    onMouseUp={this.handleMouseUp}
                    onMouseMove={this.handleMouseMove}
                    onContextMenu={(e)=>e.preventDefault()}
                    onWheel={this.handleWheel}
                />
                <TileManager
                    scene={this.scene}
                    tiles={this.state.tiles}
                    tileShouldUpdate={this.tileShouldUpdate}
                />
            </div>

        );
    }
}

export default MapboxThree;

